package ar.uade.fain.ai.tpo.dao;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Date;
import java.util.List;
import java.util.Set;

import ar.uade.fain.ai.tpo.model.Categoria;
import ar.uade.fain.ai.tpo.model.Producto;
import ar.uade.fain.ai.tpo.model.Proveedor;
import ar.uade.fain.ai.tpo.model.Unidad;

public class ProductoDAO extends CacheDAOSupport<Producto>{
	
	private static final String INSERT = 
			"INSERT INTO delivery.dbo.PRODUCTO (" +
			"	idProducto, nombre, costo, estacionDesde,estacionHasta," + 
			"	idCategoria, idProveedor, idUnidad, activo) " +
			"VALUES (?,?,?,?,?,?,?,?,1)";
	
	private final String GET_BY_NOMBRE = 
			"SELECT * FROM delivery.dbo.PRODUCTO " +
			"WHERE nombre = ? and activo = 1";
	
	private final String GET_BY_ID = 
			"SELECT * " +
			"FROM delivery.dbo.PRODUCTO " +
			"WHERE idproducto = ? and activo = 1";
	
	private final String NEXT_ID = 
			"select isnull (max(idProducto),0)+1 as id " +
			"from delivery.dbo.Producto";
	
	private final String UPDATE = 
			"UPDATE delivery.dbo.PRODUCTO SET " +
			"	IDUNIDAD = ?" +
			",	IDPROVEEDOR=?" +
			", 	IDCATEGORIA=?" +
			", 	NOMBRE=?" +
			",	COSTO=?" +
			",	ESTACIONDESDE=?" +
			",	ESTACIONHASTA=? " +
			"WHERE IDPRODUCTO = ?";

	private final String DELETE = 
			"UPDATE delivery.dbo.PRODUCTO SET " +
			"	activo = 0 " +
			"WHERE nombre = ?";
	
	private CategoriaDAO categoriaDAO;
	private UnidadDAO unidadDAO;
	private ProveedorDAO proveedorDAO;
	
	public ProductoDAO() {
		super();
	}
	
	public CategoriaDAO getCategoriaDAO() {
		return categoriaDAO;
	}

	public void setCategoriaDAO(CategoriaDAO categoriaDAO) {
		this.categoriaDAO = categoriaDAO;
	}

	public UnidadDAO getUnidadDAO() {
		return unidadDAO;
	}

	public void setUnidadDAO(UnidadDAO unidadDAO) {
		this.unidadDAO = unidadDAO;
	}

	public ProveedorDAO getProveedorDAO() {
		return proveedorDAO;
	}

	public void setProveedorDAO(ProveedorDAO proveedorDAO) {
		this.proveedorDAO = proveedorDAO;
	}

	public Producto buscarPorNombre (final String nombre){
		Set<Producto> productosEnCache = buscarEnCache(new Selector<Producto>() {
			@Override
			public boolean aceptar(Producto entidad) {
				return entidad.getNombre().equalsIgnoreCase(nombre);
				
			}
		});
		if(productosEnCache.isEmpty()){
			return load(nombre);
		}else{
			return productosEnCache.iterator().next();
		}
	}

	private Producto load(final String nombre) {
		List<Producto> productosEnBase = database().select(GET_BY_NOMBRE, 
				new ParameterSetter() {
			@Override
			public void setParametros(PreparedStatement statement) 
					throws SQLException {
				statement.setString(1, nombre);
				
			}
		}, new RowMapper<Producto>() {
			@Override
			public Producto map(ResultSet rs) throws SQLException {
				Producto producto = new Producto();
				//TODO: completar
				return producto;
			}
		});
		if(productosEnBase.isEmpty()){
			return null;
		}
		else{
			Producto producto = productosEnBase.get(0);
			agregarACache(producto);
			return productosEnBase.get(0);
		}
	}
	
	public Producto buscarPorId(final Long id){
		Set<Producto> enCache = buscarEnCache(new Selector<Producto>() {
			
			@Override
			public boolean aceptar(Producto entidad) {
				return (entidad.getId().equals(id));
			}
		});
		
		if(!enCache.isEmpty()){
			return enCache.iterator().next();
		}
		else{
			List<Producto> enBase = database().select(GET_BY_ID, 
					id, new RowMapper<Producto>() {
				@Override
				public Producto map(ResultSet rs) throws SQLException {
					Producto producto = new Producto();
					producto.setId(rs.getLong("idproducto"));
					producto.setNombre(rs.getString("nombre"));
					producto.setCosto(rs.getDouble("costo"));
					producto.setEstacionDesde(rs.getDate("estaciondesde"));
					producto.setEstacionHasta(rs.getDate("estacionhasta"));
					producto.setCategoria(categoriaDAO.buscarPorId(rs.getLong("idcategoria")));
					producto.setUnidad(unidadDAO.buscarPorId(rs.getLong("idunidad")));
					producto.setProveedor(proveedorDAO.buscarPorId(rs.getLong("idproveedor")));
					return producto;
				}
			});
			if (enBase.isEmpty()){
				return null;
			}
			else{
				
				Producto producto = enBase.get(0);
				agregarACache(producto);
				return producto;
			}
		}
		
	}
	
	public void guardar (final Producto producto){
		final long id = database().selectNextId(NEXT_ID);
		database().insert(INSERT, new ParameterSetter() {
			@Override
			public void setParametros(final PreparedStatement statement) 
					throws SQLException {
				int i = 1;
				statement.setLong(i++, id);
				statement.setString(i++,producto.getNombre());
				statement.setDouble(i++, producto.getCosto());
				Date estacionDesde = producto.getEstacionDesde();
				if (estacionDesde != null){
					statement.setDate(i++,new java.sql.Date(estacionDesde.getTime()));
				}
				else{
					statement.setDate(i++,null);
				}
				Date estacionHasta = producto.getEstacionHasta();
				if (estacionHasta != null){
					statement.setDate(i++,new java.sql.Date(estacionHasta.getTime()));
				}
				else{
					statement.setDate(i++, null);
				}
				Categoria categoria = producto.getCategoria();
				Proveedor proveedor = producto.getProveedor();
				Unidad unidad = producto.getUnidad();
				if (categoria == null || proveedor == null || unidad == null){
					throw new NullPointerException("Hay campos vacios");
				}
				else{
					statement.setLong(i++, categoria.getId());
					statement.setLong(i++, unidad.getId());
					statement.setLong(i++, proveedor.getId());
				}
			}
		});
	}
	
	public void eliminar (final Long id){
		Set<Producto> enCache = buscarEnCache(new Selector<Producto>() {
			@Override
			public boolean aceptar(Producto entidad) {
				return (entidad.getId() == id);
			}
		});
		if(enCache != null){
			enCache.remove(enCache.iterator().next());
		}
		database().update(DELETE, ParameterSetter.Factory.idOnly(id));
	}
	
	public void modificar (final Producto producto){
		database().update(UPDATE, new ParameterSetter() {
			@Override
			public void setParametros(PreparedStatement statement) throws SQLException {
				statement.setLong(1, producto.getCategoria().getId());
				statement.setLong(2, producto.getProveedor().getId());
				statement.setLong(3, producto.getCategoria().getId());
				statement.setString(4, producto.getNombre());
				statement.setDouble(5, producto.getCosto());
				if(producto.getEstacionDesde() == null) {
					statement.setNull(6, Types.DATE);
				} else {
					statement.setDate(6, new java.sql.Date (producto.getEstacionDesde().getTime()));
				}
				if (producto.getEstacionHasta() == null) {
					statement.setNull(7, Types.DATE);
				} else {
					statement.setDate(7, new java.sql.Date (producto.getEstacionHasta().getTime()));
				}
				statement.setLong(8, producto.getId());
			}
		});
		agregarACache(producto);
	}

}
